# -*- coding: utf-8 -*-

from operator import truediv
from re import S
from turtle import color
from wxb_mainFrame import *
from runningDialog import *
from settingsDialog import *
from pdfDirGenerator import *
from aboutDialog import *
from dirFormator import *
import utils
import wx
import os
import time

def getCurTimeStr():
    tm = time.localtime()
    time_str = '[%04d/%02d/%02d %02d:%02d:%02d]'\
        % (tm.tm_year, tm.tm_mon, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec)
    return time_str

WELCOME_STR = "欢迎使用 PDF Dir Generator (^3^)"

class MainFrame(wxb_mainFrame, PDFDirGenerator):
    
    def __init__(self, parent):
        # super().__init__(parent)
        wxb_mainFrame.__init__(self, parent)
        PDFDirGenerator.__init__(self, None, False)
        
        self.m_bpButton_pdfsource.SetBitmap( wx.Bitmap( u"./assets/default_folder_opened.png", wx.BITMAP_TYPE_ANY ) )
        self.m_bpButton_dirsource.SetBitmap( wx.Bitmap( u"./assets/default_folder_opened.png", wx.BITMAP_TYPE_ANY ) )
        self.SetIcon(wx.Icon(".\\assets\\logo.ico"))

        self.dirformator = DirFormator(None)
        
        self.print2screen(WELCOME_STR, isNewline=False, isTime=True)
    
        self.__status_choose_pdf()
        
    ## 在屏幕上打印信息
    def print2screen(self, txt, isNewline = True, isTime=True, isBold=False, isItalic=False, color=(0,0,0), fontsize=10):
        
        self.m_richText_screen.SetInsertionPointEnd()
        
        self.m_richText_screen.BeginFontSize(fontsize)
        self.m_richText_screen.BeginTextColour(color)
        if isBold: self.m_richText_screen.BeginBold()
        if isItalic: self.m_richText_screen.BeginItalic()
        if isTime: txt = getCurTimeStr() + ' ' + txt
        if isNewline: self.m_richText_screen.Newline()        
        self.m_richText_screen.WriteText(txt)
        
        if isItalic: self.m_richText_screen.EndItalic()
        if isBold: self.m_richText_screen.EndBold()
        self.m_richText_screen.EndTextColour()
        self.m_richText_screen.EndFontSize()
        
        self.m_richText_screen.ShowPosition(self.m_richText_screen.GetInsertionPoint())
        
    def OnClearScreen(self, event):
        
        self.m_richText_screen.Clear()
        self.print2screen(WELCOME_STR, isNewline=False, isTime=True)
        
        event.Skip()
        return super().OnClearScreen(event)
    
    def __status_choose_pdf(self):
        self.m_statusBar1.SetStatusText("  tip: 请选择一个PDF文件/配置文件: File > Open", 0)
    
    def __status_choose_dir(self):
        self.m_statusBar1.SetStatusText("  tip: 请选择一个目录文件/配置文件: File > Open", 0)
    
    def __status_format_dir(self):
        self.m_statusBar1.SetStatusText("  tip: 请格式化目录: Run > Format dir", 0)
    
    def __status_generate_dir(self):
        self.m_statusBar1.SetStatusText("  tip: 请生成目录: Run > Generate dir", 0)
    
    def __status_modify_dir(self):
        self.m_statusBar1.SetStatusText("  tip: 请先修改目录再生成目录: Run > Generate dir", 0)
    
    ## 选择输入PDF路径
    def __change_pdf(self, newpath):
        
        utils.CURRENT_SETTINGS["PDF_INPUT_PATH"] = newpath
        utils.IS_FORMATED = False
        self.m_textCtrl_pdfsource.SetValue(utils.CURRENT_SETTINGS["PDF_INPUT_PATH"])
        self.print2screen("选择 PDF 文件: %s" 
                          % utils.CURRENT_SETTINGS["PDF_INPUT_PATH"],
                          isTime=True)
        self.__status_choose_dir()
    
    def OnSelectPDF(self, event):
        
        with wx.FileDialog(self, "Select PDF File ...",
                           defaultDir=os.getcwd(),
                           style=wx.FD_OPEN,
                           wildcard='*.pdf') as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                newpath = dlg.GetPath()                
                self.__change_pdf(newpath)
                
        event.Skip()
        return super().OnSelectPDF(event)
    
    def OnbpSelectPDF(self, event):

        with wx.FileDialog(self, "Select PDF File ...",
                           defaultDir=os.getcwd(),
                           style=wx.FD_OPEN,
                           wildcard='*.pdf') as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                newpath = dlg.GetPath()
                self.__change_pdf(newpath)
                
        event.Skip()
        return super().OnbpSelectPDF(event)
    

    ## 设置目录
    def __change_dir(self, newpath):
        utils.CURRENT_SETTINGS["DIR_INPUT_PATH"] = newpath
        utils.IS_FORMATED = False
        self.m_textCtrl_dirsource.SetValue(utils.CURRENT_SETTINGS["DIR_INPUT_PATH"])
        self.print2screen("选择 Dir 文件: %s" 
                          % utils.CURRENT_SETTINGS["DIR_INPUT_PATH"],
                          isTime=True)
        
        self.__status_format_dir()
    
    def OnSeletcDir(self, event):
        
        with wx.FileDialog(self, "Select Dir File ...",
                           defaultDir=os.getcwd(),
                           style=wx.FD_OPEN,
                           wildcard="*.txt") as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                newpath = dlg.GetPath()
                self.__change_dir(newpath)
                
        event.Skip()
        return super().OnSeletcDir(event)
    
    def OnbpSelectDir(self, event):
        
        with wx.FileDialog(self, "Select Dir File ...",
                           defaultDir=os.getcwd(),
                           style=wx.FD_OPEN,
                           wildcard="*.txt") as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                newpath = dlg.GetPath()
                self.__change_dir(newpath)
        event.Skip()
        return super().OnbpSelectDir(event)
    
   
    
    ## 选择配置文件
    def __print_params(self):
        self.print2screen("* PDF input path  : %s" % utils.CURRENT_SETTINGS["PDF_INPUT_PATH"], isTime=False, color=(130,130,130))
        self.print2screen("* PDF output path : %s" % utils.CURRENT_SETTINGS["PDF_OUTPUT_PATH"], isTime=False, color=(130,130,130))
        self.print2screen("* Dir input path  : %s" % utils.CURRENT_SETTINGS["DIR_INPUT_PATH"], isTime=False, color=(130,130,130))
        self.print2screen("* offset          : %s" % utils.CURRENT_SETTINGS["OFFSET"], isTime=False, color=(130,130,130))
        self.print2screen("* prefix          : %s" % utils.CURRENT_SETTINGS["PREFIX"], isTime=False, color=(130,130,130))
        self.print2screen("* delimiter       : %s" % utils.CURRENT_SETTINGS["DELIMITER"], isTime=False, color=(130,130,130))
        self.print2screen("* level marker    : %s" % utils.CURRENT_SETTINGS["LEVEL_MARKER"], isTime=False, color=(130,130,130))
        self.print2screen("* pre-level       : %s" % utils.CURRENT_SETTINGS["PRE_LEVEL"], isTime=False, color=(130,130,130))
        self.print2screen("* pre-title       : %s" % utils.CURRENT_SETTINGS["PRE_TITLE"], isTime=False, color=(130,130,130))
        self.print2screen("* dir-log path    : %s" % utils.CURRENT_SETTINGS["DIR_LOG_PATH"], isTime=False, color=(130,130,130))
        self.print2screen("* dir-format path : %s" % utils.CURRENT_SETTINGS["DIR_FORMAT_PATH"], isTime=False, color=(130,130,130))
       
    def OnPrintParams(self, event):
        
        self.__print_params()
        
        event.Skip()
        return super().OnPrintParams(event)
    
    def OnSelectConf(self, event):
        
        with wx.FileDialog(self, "Select Conf File ...",
                           defaultDir=os.getcwd(),
                           style=wx.FD_OPEN,
                           wildcard="*.conf") as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                conf_path = dlg.GetPath()
                params = utils.parse_setting(conf_path)
                # print(params)
                for key in params:
                    if key in utils.CURRENT_SETTINGS:
                        utils.CURRENT_SETTINGS[key] = params[key]
                utils.IS_FORMAT_DIR_FIRST = int(params["IS_FORMAT_DIR_FIRST"])
                utils.IS_PRINT_ACTICE_ONLY = int(params["IS_PRINT_ACTICE_ONLY"])
                utils.IS_PRINT_PROCESS = int(params["IS_PRINT_PROCESS"])
                utils.IS_FORMATED = False
                self.m_textCtrl_pdfsource.SetValue(utils.CURRENT_SETTINGS["PDF_INPUT_PATH"])
                self.m_textCtrl_dirsource.SetValue(utils.CURRENT_SETTINGS["DIR_INPUT_PATH"])

                # 显示参数
                self.print2screen("选择配置文件: %s" % conf_path, isTime=True)
                self.__print_params()
                self.m_checkBox1_adviceOnly.SetValue(utils.IS_PRINT_ACTICE_ONLY)
                
        event.Skip()
        return super().OnSelectConf(event)
    
    ## 格式化目录
    def OnSelectAdviceOnly(self, event):
        utils.IS_PRINT_ACTICE_ONLY = self.m_checkBox1_adviceOnly.GetValue()
        
        event.Skip()
        return super().OnSelectAdviceOnly(event)    
    
    def OnSelectFormatFirst(self, event):
        utils.IS_FORMAT_DIR_FIRST = self.m_checkBox_formatdir.GetValue()
        
        event.Skip()
        return super().OnSelectFormatFirst(event)
    
    def OnSelectPrintProcess(self, event):
        utils.IS_PRINT_PROCESS = self.m_checkBox_printprocess.GetValue()
        
        event.Skip()
        return super().OnSelectPrintProcess(event)
    
    def __print_advice(self, out_lines, out_err_codes, err_line_nums):
        for lid in err_line_nums:
            err_msg = getErrMsg(out_err_codes[lid])
            err_color = getErrColor(out_err_codes[lid])
            adv_str = '[Line %3d] %s ==> %s'\
                % (lid+1, out_lines[lid][:-1], ';'.join(err_msg))
            self.print2screen(adv_str, isTime=False, color=err_color)
    
    def __print_formatdir(self, out_lines, out_err_codes, err_line_nums):
        cnt = 0
        for i in range(len(out_lines)):
            if i == err_line_nums[cnt]:
                err_msg = getErrMsg(out_err_codes[i])
                err_color = getErrColor(out_err_codes[i])
                adv_str = '[%3d] %s ==> %s'\
                    % (i+1, out_lines[i][:-1], ';'.join(err_msg))
                self.print2screen(adv_str, isTime=False, color=err_color)
                cnt += 1
            else:
                adv_str = '[%3d] %s'\
                    % (i+1, out_lines[i][:-1])
                self.print2screen(adv_str, isTime=False, color=(0,255,0))
                
    def __formatDir(self):
        
        self.dirformator.reset(utils.CURRENT_SETTINGS)
        [out_lines, out_err_codes, err_line_nums] = self.dirformator.run()
        
        # 标记为已格式化
        utils.IS_FORMATED = True
        # 修改输入目录
        utils.CURRENT_SETTINGS["DIR_INPUT_PATH"] = self.dirformator.dir_format_path
        self.m_textCtrl_dirsource.SetValue(utils.CURRENT_SETTINGS["DIR_INPUT_PATH"])
        
        self.print2screen("格式化后的目录为: %s"
                          % utils.CURRENT_SETTINGS["DIR_INPUT_PATH"])
        if utils.IS_PRINT_ACTICE_ONLY:
            self.__print_advice(out_lines, out_err_codes, err_line_nums)
        else:
            self.__print_formatdir(out_lines, out_err_codes, err_line_nums)
        
        res = True
        if len(out_err_codes):
            with wx.MessageDialog(self, "格式化后的目录文件可能手动需要修改", 
                                  "警告", style=wx.OK | wx.ICON_WARNING) as dlg:
                dlg.ShowModal()
            self.__status_modify_dir()
            res = False
        else:
            self.__status_generate_dir()

        return res
        
    def OnFormatDir(self, event):
        
        self.__formatDir()
        
        event.Skip()
        return super().OnFormatDir(event)
    
    ## 生成目录
    def run(self, dlg:RunnningDialog):
        
        res = False
             
        with open(self.dir_path, 'r', encoding='utf-8') as fin:
            pdf_reader = PyPDF2.PdfFileReader(self.pdf_input_path)
            pdf_writer = PyPDF2.PdfFileWriter()
            
            pdf_writer.cloneDocumentFromReader(pdf_reader)
            self.dir_parents = [None]
            
            lines = fin.readlines()
            dprocess = 95.0 / len(lines)
            
            for i, oline in enumerate(lines):
                line = oline.strip()
                level = self.getLevel(oline)
                divide_pos = self.getDividePos(line)
                page = int(line[divide_pos+1:]) + self.offset
                # 添加书签
                if level >= len(self.dir_parents):
                    self.dir_parents.append(None)
                self.dir_parents[level] = pdf_writer.addBookmark(
                    line[0:divide_pos], page-1, self.dir_parents[level-1]
                )
                # 进度条
                dlg.m_gauge_running.SetValue(
                    dlg.m_gauge_running.GetValue() + dprocess
                )
                dlg.m_staticText_run.SetLabel("正在处理 %d/%d ..." % (i+1, len(lines)))
                
                # 打印中间信息
                if utils.IS_PRINT_PROCESS:
                    self.print2screen(" [%3d/%3d finished] level: %d, title: %s, page: %d"
                          % ( i+1, len(lines), level, line[0:divide_pos], page ),
                          isTime=False, color=(130,130,130))
                
            # 设置输出目录                        
            if len(self.pdf_output_path) == 0:
                dot_pos = self.pdf_input_path.rfind('.')
                self.pdf_output_path = self.pdf_input_path[0:dot_pos] + '(书签).pdf'
            else:
                output_dot_pos = self.pdf_output_path.rfind('.')
                output_base_pos = self.pdf_output_path.rfind('\\')
                if output_dot_pos != -1 and output_base_pos < output_dot_pos:
                    # 给定文件名
                    pass 
                else:
                    # 给定文件夹
                    dot_pos = self.pdf_input_path.rfind('.')
                    base_pos = self.pdf_input_path.rfind('\\')
                    base_name = self.pdf_input_path[base_pos+1:dot_pos]
                    if self.pdf_output_path[-1] == '\\':
                        self.pdf_output_path = self.pdf_output_path + base_name + '(书签).pdf'
                    else:
                        self.pdf_output_path = self.pdf_output_path + '\\' + base_name + '(书签).pdf'
            
            with open(self.pdf_output_path, 'wb') as fout:
                pdf_writer.write(fout)
                res = True
                dlg.m_gauge_running.SetValue(100)
                dlg.m_staticText_run.SetLabel("成功添加书签!")
                
        return res

    def __generateDir(self):
        
        self.print2screen("开始添加书签:\n     %s\n --> %s" 
                          % (utils.CURRENT_SETTINGS["DIR_INPUT_PATH"], utils.CURRENT_SETTINGS["PDF_INPUT_PATH"]))
        frame2 = RunnningDialog(None)
        frame2.Show(True)
        self.reset(utils.CURRENT_SETTINGS)
        if self.run(frame2):
            self.print2screen("书签添加成功: %s" % self.pdf_output_path, color=(0,255,0))
            self.__status_choose_pdf()
        else:
            self.print2screen("书签添加失败 :(", color=(255,0,0))
            self.__status_generate_dir()
    
    def OnGenerateDir(self, event):
        
        self.__generateDir()
        

        event.Skip()
        return super().OnGenerateDir(event)
    
    def OnBTGenerateDir(self, event):
    
        isok = True    
        # 判断是否格式化
        if utils.IS_FORMAT_DIR_FIRST and utils.IS_FORMATED == False:
            isok = self.__formatDir()
        # 生成目录
        if isok:
            self.__generateDir()
        
        
        
        event.Skip()
        return super().OnBTGenerateDir(event)
    
    ## 打开设置界面
    def OnClickSettings(self, event):
        
        with SettingsDialog(self) as dlg:
            dlg.m_textCtrl_offset.SetValue(utils.CURRENT_SETTINGS["OFFSET"])
            dlg.m_textCtrl_prefix.SetValue(utils.CURRENT_SETTINGS["PREFIX"])
            dlg.m_textCtrl_delimiter.SetValue(utils.CURRENT_SETTINGS["DELIMITER"])
            dlg.m_textCtrl_levelmarker.SetValue(utils.CURRENT_SETTINGS["LEVEL_MARKER"])
            dlg.m_choice_prelevel.SetSelection(int(utils.CURRENT_SETTINGS["PRE_LEVEL"])-1)
            dlg.m_textCtrl_pretitle.SetValue(utils.CURRENT_SETTINGS["PRE_TITLE"])
            dlg.m_textCtrl_pdfoutputpath.SetValue(utils.CURRENT_SETTINGS["PDF_OUTPUT_PATH"])
            dlg.m_textCtrl_dirlogpath.SetValue(utils.CURRENT_SETTINGS["DIR_LOG_PATH"])
            dlg.m_textCtrl_formatpath.SetValue(utils.CURRENT_SETTINGS["DIR_FORMAT_PATH"])
            
            dlg.ShowModal()
            
        
        return super().OnClickSettings(event)

    def OnClickAbout(self, event):
        
        with AboutDialog(self) as dlg:
            dlg.ShowModal()
        
        return super().OnClickAbout(event)